/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_announce_server.h"
#include "sle_announce_service.h"
#include "sle_adapter_manager.h"
#include "sle_utils_remote_observer_list.h"
#include "sle_hilog.h"
#include "sle_advanced_setting_manager.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
class SleAnnounceServer::SleAnnounceServerImpl {
public:
    SleAnnounceServerImpl();
    ~SleAnnounceServerImpl();

    SleErrorCode CheckOperation();
    SleErrorCode RegisterAnnounceCallback(const sptr<ISleAnnounceCallback> &callback);
    SleErrorCode UnregisterAnnounceCallback(const sptr<ISleAnnounceCallback> &callback);
    SleErrorCode CreateAnnounceId(uint8_t &announceId);
    SleErrorCode RemoveAnnounceId(uint8_t announceId);
    SleErrorCode StartAnnounce(uint8_t announceId, AnnounceData &data, AnnounceParam &param);
    SleErrorCode StopAnnounce(uint8_t announceId);
    SleErrorCode SetAnnounceState(uint8_t announceId, SleAnnounceState state);
    SleErrorCode GetDefaultAnnounceParamConfig(SleAnnounceParam &announceConfig);

    class SleAnnounceCallbackImpl;
    std::unique_ptr<SleAnnounceCallbackImpl> callbackImpl_ = nullptr;

    SleAnnounceService *anneService_ = nullptr;
    SleAdapterManager *adapterManager_ = nullptr;
    SleRemoteObserverList<ISleAnnounceCallback> callbacks_;

private:
    std::map<uint8_t, SleAnnounceState> announceIdMap_;
    std::mutex lock_;
};

class SleAnnounceServer::SleAnnounceServerImpl::SleAnnounceCallbackImpl : public IAnnounceCallback {
public:
    SleAnnounceCallbackImpl(SleAnnounceServer::SleAnnounceServerImpl &impl) : impl_(impl){};
    ~SleAnnounceCallbackImpl() override = default;

    void OnAnnounceStateChange(uint8_t announceId, SleAnnounceState state, bool terminal) override
    {
        SLE_LOGD("OnAnnounceStateChange In");
        impl_.SetAnnounceState(announceId, state);
        impl_.callbacks_.ForEach([announceId, state, terminal](sptr<ISleAnnounceCallback> callback) {
            callback->OnAnnounceStateChange(announceId, state, terminal);
        });
    }

private:
    SleAnnounceServer::SleAnnounceServerImpl &impl_;
};

SleAnnounceServer::SleAnnounceServerImpl::SleAnnounceServerImpl()
{
    SLE_LOGI("SleAnnounceServerImpl In");
    callbackImpl_ = std::make_unique<SleAnnounceCallbackImpl>(*this);
    SLE_ASSERT_AND_RETURN_LOG(callbackImpl_, "callbackImpl null error!");

    anneService_ = SleAnnounceService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(anneService_, "announce service instance null error!");

    SleErrorCode ret = anneService_->RegisterAnnounceCallback(*callbackImpl_.get());
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_NO_ERROR, "register announce callback failed!");

    adapterManager_ = SleAdapterManager::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(adapterManager_, "adapter manager instance null error!");
}

SleAnnounceServer::SleAnnounceServerImpl::~SleAnnounceServerImpl()
{
    SLE_LOGI("~SleAnnounceServerImpl In");
    SLE_ASSERT_AND_RETURN_LOG(callbackImpl_, "callbackImpl null error!");
    SLE_ASSERT_AND_RETURN_LOG(anneService_, "announce service instance null error!");
    SleErrorCode ret = anneService_->UnregisterAnnounceCallback(*callbackImpl_.get());
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_NO_ERROR, "unregister announce callback failed!");
}

SleErrorCode SleAnnounceServer::SleAnnounceServerImpl::CheckOperation()
{
    SLE_ASSERT_AND_RETURN_RET_LOG(anneService_, SLE_ERR_NOT_READY, "announce service instance null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(adapterManager_, SLE_ERR_NOT_READY, "adapter manager instance null error!");
    int32_t state;
    SleErrorCode ret = adapterManager_->GetState(state);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "get sle state failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(state == SLE_HOST_STATE_ENABLED, SLE_ERR_STATUS_WRONG,
        "host state(%{public}s) error!", SleDeviceStateStr(state));
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::SleAnnounceServerImpl::RegisterAnnounceCallback(const sptr<ISleAnnounceCallback> &callback)
{
    auto func = std::bind(&SleAnnounceServer::SleAnnounceServerImpl::UnregisterAnnounceCallback, this, std::placeholders::_1);
    SLE_ASSERT_AND_RETURN_RET_LOG(callbacks_.Register(callback, func), SLE_ERR_FAILED, "register announce callback failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::SleAnnounceServerImpl::UnregisterAnnounceCallback(const sptr<ISleAnnounceCallback> &callback)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(callbacks_.Unregister(callback), SLE_ERR_FAILED, "unregister announce callback failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::SleAnnounceServerImpl::CreateAnnounceId(uint8_t &announceId)
{
    SLE_LOGD("CreateAnnounceId In");
    std::lock_guard<std::mutex> lock(lock_);
    for(uint8_t id = SLE_DEFAULT_ANNOUNCE_ID; id <= SLE_MAX_ANNOUNCE_ID_NUM; ++id) {
        auto iter = announceIdMap_.find(id);
        if(iter != announceIdMap_.end()) {
            continue;
        }
        announceIdMap_.insert(std::make_pair(id, SLE_ANNOUNCE_DISABLED_STATE));
        announceId = id;
        return SLE_NO_ERROR;
    }
    SLE_LOGE("announce id already max error!");
    return SLE_ERR_FAILED;
}

SleErrorCode SleAnnounceServer::SleAnnounceServerImpl::RemoveAnnounceId(uint8_t announceId)
{
    SLE_LOGD("RemoveAnnounceId In");
    std::lock_guard<std::mutex> lock(lock_);
    SLE_ASSERT_AND_RETURN_RET_LOG(!announceIdMap_.empty(), SLE_ERR_FAILED, "announce id list already null error!");
    auto iter = announceIdMap_.find(announceId);
    SLE_ASSERT_AND_RETURN_RET_LOG(iter != announceIdMap_.end(), SLE_ERR_FAILED, "announce id already remove error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(iter->second == SLE_ANNOUNCE_DISABLED_STATE, SLE_ERR_STATUS_WRONG,
        "announce state(%{public}s) error", SleAnnounceStateStr(iter->second));
    announceIdMap_.erase(iter);
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::SleAnnounceServerImpl::StartAnnounce(
    uint8_t announceId, AnnounceData &data, AnnounceParam &param)
{
    SLE_LOGD("StartAnnounce In");
    {
        std::lock_guard<std::mutex> lock(lock_);
        auto iter = announceIdMap_.find(announceId);
        SLE_ASSERT_AND_RETURN_RET_LOG(iter != announceIdMap_.end(), SLE_ERR_FAILED, "announce id not exist error!");
        SLE_ASSERT_AND_RETURN_RET_LOG(iter->second == SLE_ANNOUNCE_DISABLED_STATE, SLE_ERR_STATUS_WRONG,
            "current announce state(%{public}s) error!", SleAnnounceStateStr(iter->second));
    }
    SleErrorCode ret = anneService_->StartAnnounce(announceId, data, param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "start announce failed!");
    SetAnnounceState(announceId, SLE_ANNOUNCE_ENABLING_STATE);
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::SleAnnounceServerImpl::StopAnnounce(uint8_t announceId)
{
    SLE_LOGD("StopAnnounce In");
    {
        std::lock_guard<std::mutex> lock(lock_);
        auto iter = announceIdMap_.find(announceId);
        SLE_ASSERT_AND_RETURN_RET_LOG(iter != announceIdMap_.end(), SLE_ERR_FAILED, "announce id not exist error!");
        SLE_ASSERT_AND_RETURN_RET_LOG(iter->second == SLE_ANNOUNCE_ENABLED_STATE, SLE_ERR_STATUS_WRONG,
            "current announce state(%{public}s) error!", SleAnnounceStateStr(iter->second));
    }
    SleErrorCode ret = anneService_->StopAnnounce(announceId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "stop announce failed!");
    SetAnnounceState(announceId, SLE_ANNOUNCE_DISABLING_STATE);
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::SleAnnounceServerImpl::SetAnnounceState(uint8_t announceId, SleAnnounceState state)
{
    SLE_LOGD("SetAnnounceState In");
    std::lock_guard<std::mutex> lock(lock_);
    auto iter = announceIdMap_.find(announceId);
    SLE_ASSERT_AND_RETURN_RET_LOG(iter != announceIdMap_.end(), SLE_ERR_FAILED, "announce id not exist error!");
    iter->second = state;
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::SleAnnounceServerImpl::GetDefaultAnnounceParamConfig(SleAnnounceParam &announceConfig)
{
    SLE_LOGD("GetDefaultAnnounceParamConfig In");
    SleErrorCode ret = AdvancedSettingManager::GetInstance()->GetDefaultAnnounceParamConfig(announceConfig);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "get announce param config failed(%{public}d)!", ret);
    return SLE_NO_ERROR;
}

SleAnnounceServer::SleAnnounceServer()
{
    SLE_LOGD("SleAnnounceServer In");
    pimpl_ = std::make_unique<SleAnnounceServerImpl>();
    SLE_ASSERT_AND_RETURN_LOG(pimpl_, "pimpl null error!");
}

SleAnnounceServer::~SleAnnounceServer(){}

SleErrorCode SleAnnounceServer::RegisterAnnounceCallback(const sptr<ISleAnnounceCallback> &callback)
{
    SLE_LOGD("RegisterAnnounceCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback, SLE_ERR_INVALID_PARAM, "callback null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->RegisterAnnounceCallback(callback);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "register announce callback failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::UnregisterAnnounceCallback(const sptr<ISleAnnounceCallback> &callback)
{
    SLE_LOGD("UnregisterAnnounceCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback, SLE_ERR_INVALID_PARAM, "callback null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->UnregisterAnnounceCallback(callback);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "unregister announce callback failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::CreateAnnounceId(uint8_t &announceId)
{
    SLE_LOGD("CreateAnnounceId In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_CHECKOUT_FAILED, "check operation failed!");
    ret = pimpl_->CreateAnnounceId(announceId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "create announce id failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::RemoveAnnounceId(uint8_t announceId)
{
    SLE_LOGD("RemoveAnnounceId In");
    SLE_ASSERT_AND_RETURN_RET_LOG(announceId >= SLE_DEFAULT_ANNOUNCE_ID, SLE_ERR_INVALID_PARAM, "announce id error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(announceId < SLE_MAX_ANNOUNCE_ID_NUM, SLE_ERR_INVALID_PARAM, "announce id error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_CHECKOUT_FAILED, "check operation failed!");
    ret = pimpl_->RemoveAnnounceId(announceId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "remove announce id failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::StartAnnounce(uint8_t announceId, AnnounceData &data, AnnounceParam &param)
{
    SLE_LOGD("StartAnnounce In");
    SLE_ASSERT_AND_RETURN_RET_LOG(announceId >= SLE_DEFAULT_ANNOUNCE_ID, SLE_ERR_INVALID_PARAM, "announce id error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(announceId < SLE_MAX_ANNOUNCE_ID_NUM, SLE_ERR_INVALID_PARAM, "announce id error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_CHECKOUT_FAILED, "check operation failed!");
    ret = pimpl_->StartAnnounce(announceId, data, param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "start announce failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::StopAnnounce(uint8_t announceId)
{
    SLE_LOGD("StopAnnounce In");
    SLE_ASSERT_AND_RETURN_RET_LOG(announceId >= SLE_DEFAULT_ANNOUNCE_ID, SLE_ERR_INVALID_PARAM, "announce id error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(announceId < SLE_MAX_ANNOUNCE_ID_NUM, SLE_ERR_INVALID_PARAM, "announce id error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_CHECKOUT_FAILED, "check operation failed!");
    ret = pimpl_->StopAnnounce(announceId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "stop announce failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleAnnounceServer::GetDefaultAnnounceParamConfig(SleAnnounceParam &announceConfig)
{
    SLE_LOGD("GetDefaultAnnounceParamConfig In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_CHECKOUT_FAILED, "check operation failed(%{public}d)!", ret);
    ret = pimpl_->GetDefaultAnnounceParamConfig(announceConfig);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "get announce param config failed(%{public}d)!", ret);
    return SLE_NO_ERROR;
}

} // SleStandard
} // NearLink
} // Ohos